﻿using CPPEI.Coolzon.Common;
using CPPEI.Coolzon.Server.ServiceImplement;
using CPPEI.Coolzon.Service;
using CPPEI.Coolzon.ServiceImp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;

namespace CPPEI.Coolzon.Server
{
    class Program
    {
        private static ServiceHost s_mainServiceHost;
        private static ServiceHost s_dataServiceHost;
        private static ServiceHost s_syncServiceHost;
        private static IWCFServiceHost s_publishServiceHost;

        private static API.ApiService s_apiService;

        private static EventReceiver _eventReceiver;
        //private static ServiceHost s_updateServiceHost;

        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

            //Logger.Init(CZEnvironment.GetLoggerConfigFilePath());
            Logger.InitByLogDirectory(CZEnvironment.GetLogDirectory());
            CZEnvironment.Instance.Init(CZEnvironment.GetEnvironmentFilePath());

            if (false)
            {
                if (ValidateLICFile())
                {
                    Logger.InfoToTag("License", String.Format("发现license文件信息,过期时间到:{0}", License.ExpireTime.Value.ToString("yyyy-MM-dd")));
                }
                else
                {
                    Logger.WarningToTag("License", String.Format("未发现license文件信息,过期时间到:{0}", License.ExpireTime.Value.ToString("yyyy-MM-dd")));
                }

                if (License.IsTrial == License.TrialEdition)
                {
                    // 显示
                    ShowTrivalAlart();
                }

                if (License.ExpireTime.Value.Date < DateTime.Now.Date)
                {
                    Logger.WarningToTag("License", String.Format("license时间:{0}已到期", License.ExpireTime.Value.ToString("yyyy-MM-dd")));
                    Console.ReadKey();

                    CloseTrivalAlart();
                    return;
                }
            }

            Coolzon.Runtime.Metadata.Storage.InitWithDirectory(string.Format("C:\\Coolzon\\Server\\V{0}\\RuntimeStorage\\", CZEnvironment.Version2));

            _eventReceiver = new EventReceiver();
            PublishEventBus.Register(_eventReceiver);

            LoadHostConfig();

            LoadSolutions();

            VerifySolutions();

            HostApiService();
            HostSyncService();
            HostDataService();
            s_publishServiceHost = new Coolzon.ServiceImp.WCFPublishServiceHost();
            if (!s_publishServiceHost.Open())
            {
                Logger.Error("Server", "启动发布服务失败!");
            }
            HostMainService();
            //HostUpdateService();

            //HeartbeatThread heartbeatThread = new HeartbeatThread();
            //heartbeatThread.Start();

            InputLoop();

            //heartbeatThread.Stop();

            StopMainService();
            s_publishServiceHost.Close();
            StopDataService();
            StopSyncService();
            StopApiService();
            //StopUpdateService();

            Logger.InfoToTag("Server", "服务器关闭");
        }

        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            try
            {
                if (e.ExceptionObject is Exception)
                {
                    Common.Logger.ErrorToTag("Unhandled", ((Exception)e.ExceptionObject).Message);
                }
            }
            catch (Exception ex)
            {
                Common.Logger.ErrorToTag("Unhandled", ex.Message);
            }
        }

        private static void HostApiService()
        {
            Logger.InfoToTag("Server", "API服务启动中...");
            Configuration.Server.ServiceConfig serviceConfig = Configuration.Server.Config.Host.GetServiceConfig("ApiService");
            if (serviceConfig == null)
            {
                Logger.ErrorToTag("Server", "API服务启动失败，未发现ApiService配置信息");
            }
            else
            {
                try
                {
                    s_apiService = new API.ApiService();
                    s_apiService.Start(serviceConfig.IP, serviceConfig.Port);
                    Logger.InfoToTag("Server", "API服务启动成功 ip:{0}, port:{1}", serviceConfig.IP, serviceConfig.Port);
                }
                catch (Exception ex)
                {
                    Logger.ErrorToTag("Server", "API服务启动失败 ip:{0}, port:{1}, ex:{2}", serviceConfig.IP, serviceConfig.Port, ex);
                }
            }
        }

        private static void StopApiService()
        {
            Logger.InfoToTag("Server", "API服务关闭中...");
            if (s_apiService != null)
            {
                s_apiService.Stop();
            }
            Logger.InfoToTag("Server", "API服务关闭完成");
        }

        private static void LoadHostConfig()
        {
            Logger.InfoToTag("Server", "加载Host配置信息...");
            try
            {
                CPPEI.Coolzon.Configuration.Server.Config.InitHostConfig(CZEnvironment.GetHostConfigFilePath());
                Logger.InfoToTag("Server", "加载Host配置信息完毕!");
            }
            catch
            {
                Logger.Error("Server", "加载Host配置信息出错!");
            }
        }

        public static void VerifySolutions()
        {
            Logger.InfoToTag("Server", "验证方案文件版本信息...");

            if (Coolzon.Server.CacheData.ServerData.Instance.SolutionList != null)
            {
                for (int index = 0; index < Coolzon.Server.CacheData.ServerData.Instance.SolutionList.Count; index++)
                {
                    // 扫描方案的文件生成最新的方案文件版本信息的记录文件
                    try
                    {
                        SyncService.VerifySolutions(Coolzon.Server.CacheData.ServerData.Instance.SolutionList[index].Name);
                    }
                    catch (Exception ex)
                    {
                        Logger.Error("Server", string.Format("验证方案{0}失败,ex:{1}", Coolzon.Server.CacheData.ServerData.Instance.SolutionList[index].Name, ex));
                    }
                }
            }

            Logger.InfoToTag("Server", "验证方案文件版本信息完毕");
        }

        public static void LoadSolutions()
        {
            Logger.InfoToTag("Server", "加载方案列表...");

            // 读取方案到内存中
            CPPEI.Coolzon.Server.CacheData.ServerData.Instance.SolutionList = CPPEI.Coolzon.Metadata.SolutionXmlProxy.LoadSolutionList(Runtime.Metadata.Storage.GetSolutionSummaryFile());

            if (CPPEI.Coolzon.Server.CacheData.ServerData.Instance.SolutionList != null)
            {
                foreach (var solutionRef in CPPEI.Coolzon.Server.CacheData.ServerData.Instance.SolutionList)
                {
                    Logger.InfoToTag("Server", "方案:{0},Caption:{1},Version:{2},RuntimeVersion:{3}", solutionRef.Name, solutionRef.Caption, solutionRef.Version, solutionRef.RuntimeVersion);
                }
            }
            else
            {
                Logger.InfoToTag("Server", "加载方案列表完毕,没有发现任何方案");
            }
        }

        private static void HostSyncService()
        {
            Logger.InfoToTag("Server", "配置同步服务启动中...");
            Configuration.Server.ServiceConfig serviceConfig = Configuration.Server.Config.Host.GetServiceConfig("SyncService");
            Uri baseAddress = new Uri(string.Format("net.tcp://{0}:{1}/{2}/", serviceConfig.IP, serviceConfig.Port, serviceConfig.Path));

            s_syncServiceHost = new ServiceHost(typeof(SyncService), baseAddress);
            Binding binding = new NetTcpBinding();
            (binding as NetTcpBinding).ReceiveTimeout = TimeSpan.FromSeconds(300);
            (binding as NetTcpBinding).SendTimeout = TimeSpan.FromSeconds(300);
            (binding as NetTcpBinding).MaxBufferSize = 1024 * 1024 * 1024;
            (binding as NetTcpBinding).MaxReceivedMessageSize = 1024 * 1024 * 1024;
            (binding as NetTcpBinding).Security.Mode = SecurityMode.None;
            ServiceMetadataBehavior serviceMetadataBehavior = new ServiceMetadataBehavior();
            s_syncServiceHost.Description.Behaviors.Add(serviceMetadataBehavior);
            if (serviceConfig.MetadataGet)
            {
                Logger.InfoToTag("Server", "配置同步服务元数据获取开关:开启");
                Logger.InfoToTag("Server", "配置同步服务元数据获取地址:{0}mex", baseAddress);
                s_syncServiceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
            }
            else
            {
                Logger.InfoToTag("Server", "配置同步服务元数据获取开关:关闭");
            }

            s_syncServiceHost.AddServiceEndpoint(typeof(ISyncService), binding, baseAddress);
            Logger.InfoToTag("Server", "配置同步服务地址:{0}", baseAddress);

            try
            {
                s_syncServiceHost.Open();
                Logger.InfoToTag("Server", "配置同步服务启动成功");
            }
            catch (Exception ex)
            {
                Logger.Error("Server", string.Format("配置同步服务启动失败{0}{1}", Environment.NewLine, ex));
            }
        }

        private static void HostDataService()
        {
            Logger.InfoToTag("Server", "数据服务启动中...");
            Configuration.Server.ServiceConfig serviceConfig = Configuration.Server.Config.Host.GetServiceConfig("DataService");
            Uri baseAddress = new Uri(string.Format("net.tcp://{0}:{1}/{2}/", serviceConfig.IP, serviceConfig.Port, serviceConfig.Path));

            s_dataServiceHost = new ServiceHost(typeof(ServiceImplement.DataService), baseAddress);
            Binding binding = new NetTcpBinding();
            (binding as NetTcpBinding).ReceiveTimeout = TimeSpan.FromSeconds(300);
            (binding as NetTcpBinding).SendTimeout = TimeSpan.FromSeconds(300);
            (binding as NetTcpBinding).Security.Mode = SecurityMode.None;
            ServiceMetadataBehavior serviceMetadataBehavior = new ServiceMetadataBehavior();
            s_dataServiceHost.Description.Behaviors.Add(serviceMetadataBehavior);

            ServiceThrottlingBehavior serviceThrottlingBehavior = new ServiceThrottlingBehavior();
            serviceThrottlingBehavior.MaxConcurrentSessions = 10000;
            serviceThrottlingBehavior.MaxConcurrentCalls = 10000;
            serviceThrottlingBehavior.MaxConcurrentInstances = 20000;
            s_dataServiceHost.Description.Behaviors.Add(serviceThrottlingBehavior);

            if (serviceConfig.MetadataGet)
            {
                Logger.InfoToTag("Server", "数据服务元数据获取开关:开启");
                Logger.InfoToTag("Server", "数据服务元数据获取地址:{0}mex", baseAddress);
                s_dataServiceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
            }
            else
            {
                Logger.InfoToTag("Server", "数据服务元数据获取开关:关闭");
            }

            s_dataServiceHost.AddServiceEndpoint(typeof(IDataService), binding, baseAddress);
            Logger.InfoToTag("Server", "数据服务地址:{0}", baseAddress);

            try
            {
                s_dataServiceHost.Open();
                Logger.InfoToTag("Server", "数据服务启动成功");
            }
            catch (Exception ex)
            {
                Logger.Error("Server", string.Format("数据服务启动失败{0}{1}", Environment.NewLine, ex));
            }
        }

        private static void HostMainService()
        {
            Logger.InfoToTag("Server", "主服务启动中...");
            Configuration.Server.ServiceConfig serviceConfig = Configuration.Server.Config.Host.GetServiceConfig("MainService");
            Uri baseAddress = new Uri(string.Format("net.tcp://{0}:{1}/{2}/", serviceConfig.IP, serviceConfig.Port, serviceConfig.Path));

            CZEnvironment.Instance.ServerIP = serviceConfig.IP;
            CZEnvironment.Instance.ServerPort = serviceConfig.Port;

            s_mainServiceHost = new ServiceHost(typeof(MainService), baseAddress);
            Binding binding = new NetTcpBinding();
            (binding as NetTcpBinding).Security.Mode = SecurityMode.None;
            ServiceMetadataBehavior serviceMetadataBehavior = new ServiceMetadataBehavior();
            s_mainServiceHost.Description.Behaviors.Add(serviceMetadataBehavior);

            if (serviceConfig.MetadataGet)
            {
                Logger.InfoToTag("Server", "主服务元数据获取开关:开启");
                Logger.InfoToTag("Server", "主服务元数据获取地址:{0}mex", baseAddress);
                s_mainServiceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
            }
            else
            {
                Logger.InfoToTag("Server", "主服务元数据获取开关:关闭");
            }

            s_mainServiceHost.AddServiceEndpoint(typeof(IMainService), binding, baseAddress);
            Logger.InfoToTag("Server", "主服务地址:{0}", baseAddress);

            try
            {
                s_mainServiceHost.Open();
                Logger.InfoToTag("Server", "主服务启动成功");
            }
            catch (Exception ex)
            {
                Logger.Error("Server", string.Format("主服务启动失败{0}{1}", Environment.NewLine, ex));
            }
        }

        //private static void HostUpdateService()
        //{
        //    Logger.InfoToTag("Server", "更新服务启动中...");
        //    Configuration.Server.ServiceConfig serviceConfig = Configuration.Server.Config.Host.GetServiceConfig("UpdateService");
        //    Uri baseAddress = new Uri(string.Format("net.tcp://{0}:{1}/{2}/", serviceConfig.IP, serviceConfig.Port, serviceConfig.Path));

        //    s_updateServiceHost = new ServiceHost(typeof(UpdateService), baseAddress);
        //    Binding binding = new NetTcpBinding();
        //    (binding as NetTcpBinding).Security.Mode = SecurityMode.None;
        //    ServiceMetadataBehavior serviceMetadataBehavior = new ServiceMetadataBehavior();
        //    s_updateServiceHost.Description.Behaviors.Add(serviceMetadataBehavior);

        //    if (serviceConfig.MetadataGet)
        //    {
        //        Logger.InfoToTag("Server", "更新服务元数据获取开关:开启");
        //        Logger.InfoToTag("Server", "更新服务元数据获取地址:{0}mex", baseAddress);
        //        s_updateServiceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
        //    }
        //    else
        //    {
        //        Logger.InfoToTag("Server", "发布服务元数据获取开关:关闭");
        //    }

        //    s_updateServiceHost.AddServiceEndpoint(typeof(IUpdateService), binding, baseAddress);
        //    Logger.InfoToTag("Server", "更新服务地址:{0}", baseAddress);

        //    try
        //    {
        //        s_updateServiceHost.Open();
        //        Logger.InfoToTag("Server", "更新服务启动成功");
        //    }
        //    catch (Exception ex)
        //    {
        //        Logger.ErrorToTag("Server", string.Format("更新服务启动失败{0}{1}", Environment.NewLine, ex));
        //    }
        //}

        private static void StopMainService()
        {
            Logger.InfoToTag("Server", "主服务器关闭中...");
            try
            {
                s_mainServiceHost.Close();
                Logger.InfoToTag("Server", "主服务关闭成功");
            }
            catch (Exception ex)
            {
                Logger.ErrorToTag("Server", string.Format("主服务关闭失败{0}{1}", Environment.NewLine, ex));
            }
        }

        //private static void StopUpdateService()
        //{
        //    Logger.InfoToTag("Server","更新服务器关闭中...");
        //    try
        //    {
        //        s_updateServiceHost.Close();
        //        Logger.InfoToTag("Server", "更新服务关闭成功");
        //    }
        //    catch (Exception ex)
        //    {
        //        Logger.ErrorToTag("Server", string.Format("更新服务关闭失败{0}{1}", Environment.NewLine, ex));
        //    }
        //}

        private static void StopDataService()
        {
            Logger.InfoToTag("Server", "数据服务器关闭中...");
            try
            {
                s_dataServiceHost.Close();
                Logger.InfoToTag("Server", "数据服务关闭成功");
            }
            catch (Exception ex)
            {
                Logger.ErrorToTag("Server", string.Format("数据服务关闭失败{0}{1}", Environment.NewLine, ex));
            }
        }

        private static void StopSyncService()
        {
            Logger.InfoToTag("Server", "同步服务器关闭中...");
            try
            {
                s_syncServiceHost.Close();
                Logger.InfoToTag("Server", "同步服务关闭成功");
            }
            catch (Exception ex)
            {
                Logger.ErrorToTag("Server", string.Format("同步服务关闭失败{0}{1}", Environment.NewLine, ex));
            }
        }

        private static void InputLoop()
        {
            string cmd = Console.ReadLine().ToUpper();
            while (!ConsoleCMD.Execute(cmd))
            {
                cmd = Console.ReadLine().ToUpper();
            }
        }

        #region license

        private static void ShowTrivalAlart()
        {
            string fileName = string.Format("{0}CPPEI.Coolzon.TrivalAlert.exe", AppDomain.CurrentDomain.BaseDirectory);
            Process[] processArr = Process.GetProcessesByName("CPPEI.Coolzon.TrivalAlert");
            for (int index = 0; index < processArr.Length; index++)
            {
                if (string.Equals(processArr[index].MainModule.FileName, fileName, StringComparison.CurrentCultureIgnoreCase))
                {
                    processArr[index].Kill();
                }
            }
            // 启动
            ProcessStartInfo startInfo = new ProcessStartInfo();
            startInfo.Arguments = string.Format("{0} {1}", License.ExpireTime.Value.ToString("yyyy-MM-dd"), License.SerialNumber);
            startInfo.FileName = fileName;
            Process.Start(startInfo);
        }

        private static void CloseTrivalAlart()
        {
            string fileName = string.Format("{0}CPPEI.Coolzon.TrivalAlert.exe", AppDomain.CurrentDomain.BaseDirectory);
            Process[] processArr = Process.GetProcessesByName("CPPEI.Coolzon.TrivalAlert");
            for (int index = 0; index < processArr.Length; index++)
            {
                if (string.Equals(processArr[index].MainModule.FileName, fileName, StringComparison.CurrentCultureIgnoreCase))
                {
                    processArr[index].Kill();
                }
            }
        }

        /// <summary>
        /// 验证license文件
        /// </summary>
        /// <returns>true:验证通过,false:验证失败</returns>
        private static bool ValidateLICFile()
        {
            string encryptionKey = "cPPEI_cOolzOn";
            License.SerialNumber = DSAL.SN.GetSerialNumber("coolzonx1.4", "server");
            string licFilePath = string.Format("{0}\\coolzon.lic", AppDomain.CurrentDomain.BaseDirectory);
            string sn = null;
            Dictionary<string, string> kv = DSAL.LisenceFile.Load(licFilePath, encryptionKey, out sn);
            if (kv != null)
            {
                if (string.Equals(sn, License.SerialNumber))
                {
                    License.ExpireTime = Convert.ToDateTime(kv["EXPIREDATE"]);
                    License.ClientCount = Convert.ToInt32(kv["CLIENTCOUNT"]);
                    License.IsTrial = Convert.ToInt32(kv["EDITION"]);
                    // 存储到系统目录
                    PublishLICToSystem(kv);
                    return true;
                }
            }

            if (ValidateSystemLIC())
            {
                return true;
            }
            //  
            CreateTrivalLicense();
            return false;
        }

        /// <summary>
        /// 验证系统目录里的license文件
        /// </summary>
        private static bool ValidateSystemLIC()
        {
            string encryptionKey = "cPPEI_cOolzOn";
            string sn = null;
            Dictionary<string, string> kv = DSAL.LisenceFile.LoadFromSystemDir("cppei", "coolzon-server", encryptionKey, out sn);
            if (kv != null)
            {
                License.ExpireTime = Convert.ToDateTime(kv["EXPIREDATE"]);
                License.ClientCount = Convert.ToInt32(kv["CLIENTCOUNT"]);
                License.IsTrial = Convert.ToInt32(kv["EDITION"]);

                return true;
            }
            return false;
        }

        /// <summary>
        /// 发布license 文件到系统目录
        /// </summary>
        private static void PublishLICToSystem(Dictionary<string, string> kv)
        {
            string encryptionKey = "cPPEI_cOolzOn";
            DSAL.LisenceFile.SaveToSystemDir("cppei", "coolzon-server", encryptionKey, License.SerialNumber, kv);
        }

        /// <summary>
        /// 创建试用版license文件
        /// </summary>
        private static void CreateTrivalLicense()
        {
            string encryptionKey = "cPPEI_cOolzOn";
            Dictionary<string, string> kv = new Dictionary<string, string>();
            kv.Add("EXPIREDATE", DateTime.Now.AddDays(180).ToString("yyyy-MM-dd"));
            kv.Add("CLIENTCOUNT", "1");
            // trival
            kv.Add("EDITION", "1");
            DSAL.LisenceFile.SaveToSystemDir("cppei", "coolzon-server", encryptionKey, License.SerialNumber, kv);

            License.ExpireTime = DateTime.Now.AddDays(180);
            License.ClientCount = 1;
            License.IsTrial = License.TrialEdition;
        }
        #endregion
    }
}
